// Diego A. Linares - Julio 2005 - Pentacom / Autoconsulta

#include <jni.h>
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
//#include <rs232prt.h>
//#include "varios.h"



#define ENQ			0x05
#define ESC			0x1B
#define GS			0x1D
#define LF			0x0A

#define DEBUGBYTES	FALSE
#define QUEUESIZE	1024

/*int rs232Init (char *cCom);
void rs232Done ();
BOOL rs232Send (LPBYTE bBuf, DWORD dwLen);
BOOL rs232GetStatus (BYTE *bStatus);
DWORD WINAPI ReadThread (LPVOID lpParameter);
*/

//------------------------------------------------------------------------------
static HANDLE			hThread;
static HANDLE			hDrv;			// Device COM
static OVERLAPPED		wOv;			
static OVERLAPPED		rOv;			
static HANDLE			hEvtRx;			// Informa lectura de tracks

static char				cRxBuf[1024];
static WORD				wRxLen;


//-----------------------------------------------------------------------------
DWORD WINAPI ReadThread (LPVOID lpParameter) {
	int				rc;
	DWORD			dwLen, j;
	char			cBuf[1];

         //printf("readthread");

	while (hThread) {
		dwLen = 0;
		rOv.Offset = 0;
		rOv.OffsetHigh = 0;

		if (!ReadFile (hDrv, cBuf, sizeof(cBuf), &dwLen, &rOv)) {
			rc = GetLastError ();

			if (rc != ERROR_IO_PENDING) {
				//Log ("ERROR ReadFile() [%d]", rc);
				printf("error readfile");
	            continue;
		        }
			 }

		rc = GetOverlappedResult (hDrv, &rOv, &dwLen, TRUE);
		if ((!rc) || (dwLen == 0))
			continue;

		if (DEBUGBYTES) {
			for (j=0; j<dwLen; j++)
				//Log ("-%02X", (BYTE)cBuf[j]);
				printf("readthread for");
			}

		for (j=0; j < dwLen; j++) {
			cRxBuf[j] = cBuf[j];
			}

		wRxLen = (WORD)dwLen;
		SetEvent (hEvtRx);		
		}

	return (0);
	}

//------------------------------------------------------------------------------
BOOL rs232Send (LPBYTE bBuf, DWORD dwLen) {
	DWORD		dwBytes;
	DWORD		i;
	BOOL		fWrOK;

	dwBytes = 0;
	wOv.Offset = 0;
	wOv.OffsetHigh = 0;
	fWrOK = WriteFile (hDrv, bBuf, dwLen, &dwBytes, &wOv);
	if (!fWrOK) { 
		if (GetLastError() != ERROR_IO_PENDING) {
			//Log ("*** ERROR [%d] WriteFile()...\n", GetLastError());
				printf("error writefile %d",GetLastError());
			return (FALSE);
			}
		else {
			// Espero que termine el WriteFile()
			if (!GetOverlappedResult (hDrv, &wOv, &dwBytes, TRUE)) {
				//Log ("*** ERROR [%d] GetOverlappedResult()...\n", GetLastError());
				printf("error overlapped %d",GetLastError());
				return (FALSE);
				}
			}
		}

	if (DEBUGBYTES) {
		for (i=0; i<dwLen; i++)
			//Log ("+%02X", bBuf[i]);
			printf("debug send");
		}

	return (TRUE);
	}


//------------------------------------------------------------------------------
BOOL rs232GetStatus (BYTE *bStatus) {

	if (WaitForSingleObject (hEvtRx, 3000) == WAIT_TIMEOUT) {
		//Log ("*** ERROR Timeout Esperando Respuesta");
		printf("*** ERROR Timeout Esperando Respuesta");
		return (FALSE);
		}

	memcpy (bStatus, cRxBuf, wRxLen);

	return (TRUE);
	}
	
//------------------------------------------------------------------------------
void rs232Done () {

	CloseHandle (hThread);
	hThread = NULL;

	PurgeComm (hDrv, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);

	CloseHandle (wOv.hEvent);
	CloseHandle (rOv.hEvent);
	CloseHandle (hDrv);
	}

//------------------------------------------------------------------------------
int rs232Init (char *cCom) {
	int				rc;
	char			cCom_[32], cFile[32], *cPtr;
	DCB				dcb;
	COMMTIMEOUTS	CommTimeOuts;
	DWORD			dwAux;
	BYTE			bBuf[16];

	strcpy (cCom_, cCom);

	sprintf (cFile, "\\\\.\\%s", cCom_); // Nombre del Com
	cPtr = strchr (cFile, ':');
	if (cPtr != NULL)
		*(cPtr) = 0;
	else
		strcat (cCom_, ":9600,N,8,1");
    
	memset (&wOv, 0, sizeof (wOv));
	memset (&rOv, 0, sizeof (rOv));

	hDrv = CreateFile (cFile,
		GENERIC_READ | GENERIC_WRITE,
		0, NULL, OPEN_EXISTING,
		FILE_FLAG_OVERLAPPED, NULL);

	if (hDrv == INVALID_HANDLE_VALUE) {
		rc = GetLastError();
		//Log ("ERROR CreateFile() [%s] [%d]", cFile, rc);
		return (-1);
		}

	//Log ("%s - %s", cCom_, cFile);
	
	GetCommState (hDrv, &dcb);
	if (!BuildCommDCB (cCom_, &dcb))
		return (-2);
	//dcb.fParity  = 0;
	dcb.fBinary  = 1;
	dcb.fOutxCtsFlow = 0;
	dcb.fOutxDsrFlow = 0;
        dcb.BaudRate = CBR_9600;
        dcb.ByteSize = 8;             // data size, xmit, and rcv
        dcb.Parity = NOPARITY;        // no parity bit
        dcb.StopBits = ONESTOPBIT;    // one stop bit
	SetCommState (hDrv, &dcb);

	SetupComm (hDrv, QUEUESIZE, QUEUESIZE);
	CommTimeOuts.ReadIntervalTimeout = 100;			// Mas de 100 ms entre bytes -> termina paquete
	CommTimeOuts.ReadTotalTimeoutConstant = 3000;
	CommTimeOuts.ReadTotalTimeoutMultiplier = 100;
	CommTimeOuts.WriteTotalTimeoutConstant = 3000;	// 3 segundos de timeout para el WriteFile
	CommTimeOuts.WriteTotalTimeoutMultiplier = 100;
	SetCommTimeouts (hDrv, &CommTimeOuts);

	PurgeComm (hDrv, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);

	EscapeCommFunction (hDrv, SETDTR);	
//	EscapeCommFunction (hDrv, SETRTS);

	wOv.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
	if (wOv.hEvent == NULL)
		return (-2);

	rOv.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
	if (rOv.hEvent == NULL)
		return (NULL);

	hEvtRx = CreateEvent (NULL, FALSE, FALSE, NULL);

	hThread = CreateThread (NULL, 0L, ReadThread, NULL, 0L, &dwAux);
	if (hThread == NULL)
		return (NULL);


	return (0);
	}
//------------------------------------------------------------------------------
  JNIEXPORT jint JNICALL Java_sistcomptf_Comunicador_initRS232C(JNIEnv *env, jobject obj, jint COM)
{

   BYTE bStatus[512];
   char a[2];
   TCHAR *pcCommPort = TEXT("COM");
   int javaCom=1, result = -1;
   DWORD dwLen, j;

   sprintf( a, "%i", COM);

   strcat(pcCommPort,a);


   result = rs232Init(pcCommPort);
              //printf("init");




     return  result;
}
//------------------------------------------------------------------------------
 JNIEXPORT jint JNICALL Java_sistcomptf_Comunicador_get(JNIEnv *env, jobject obj)
{
    BYTE bStatus[512];
    int result = -1;
    bStatus[0] = 0x01;

    if(rs232GetStatus (bStatus)){
        result=bStatus[0];
    }

    //printf("buffer %x %x %x ",bStatus[0],bStatus[1],bStatus[2]);


    return result;
}

//---------------------------------------------------------------------------------
  JNIEXPORT jint JNICALL Java_sistcomptf_Comunicador_set(JNIEnv *env, jobject obj, jint send)
{
    BYTE bBuf[512];
    int result = -1;
    bBuf[0] = send;

    //printf("por enviar");

    if(rs232Send (bBuf, 1)){
      result = 0;
    }

    //printf("enviado");

    //rs232Done ();

    return result;
}
//---------------------------------------------------------------------------------
JNIEXPORT jint JNICALL Java_sistcomptf_Comunicador_stop(JNIEnv *env, jobject obj)
{
      rs232Done ();
      return (0);
}